﻿using System;
using System.Collections.Generic;
using System.Reflection.Emit;
using msilgc.cbuilder.CSyntaxTree;
using msilgc.cbuilder.MSILSyntaxTree;
using msilgc.CSyntaxTree;

namespace msilgc.cbuilder.CBuilder
{
    internal class ArithmeticTranslator : ITranslator {
        private readonly VariableFactory _varFactory;
        private readonly Dictionary<OpCode, Operation> _ops;

        public ArithmeticTranslator(VariableFactory varFactory) {
            _varFactory = varFactory;
            _ops = new Dictionary<OpCode, Operation> {
                                                         {OpCodes.Add, Operation.Add},
                                                         {OpCodes.Add_Ovf, Operation.Add},
                                                         {OpCodes.Add_Ovf_Un, Operation.Add},
                                                         {OpCodes.And, Operation.And},
                                                         {OpCodes.Ceq, Operation.Ceq},
                                                         {OpCodes.Clt, Operation.Clt},
                                                         {OpCodes.Clt_Un, Operation.Clt},
                                                         {OpCodes.Cgt, Operation.Cgt},
                                                         {OpCodes.Cgt_Un, Operation.Cgt},
                                                         {OpCodes.Div, Operation.Div},
                                                         {OpCodes.Div_Un, Operation.Div},
                                                         {OpCodes.Mul, Operation.Mul},
                                                         {OpCodes.Mul_Ovf, Operation.Mul},
                                                         {OpCodes.Mul_Ovf_Un, Operation.Mul},
                                                         {OpCodes.Or, Operation.Or},
                                                         {OpCodes.Rem, Operation.Rem},
                                                         {OpCodes.Rem_Un, Operation.Rem},
                                                         {OpCodes.Sub, Operation.Sub},
                                                         {OpCodes.Sub_Ovf, Operation.Sub},
                                                         {OpCodes.Sub_Ovf_Un, Operation.Sub},
                                                         {OpCodes.Xor, Operation.Xor}
                                                     };
        }

        public ICStatement TranslateAndAdd(CMethodBody methodBody, CBasicBlock currentBlock, BasicBlock block, Instruction instruction) {
            IVariable operand2 = EvaluationStackHelper.PopVariableOffEvaluationStack(currentBlock);
            IVariable operand1 = EvaluationStackHelper.PopVariableOffEvaluationStack(currentBlock);
            IVariable target = _varFactory.CreateNext(operand1.Type);
            if(!_ops.ContainsKey(instruction.Inst)) {
                throw new Exception("cannot translate: " + instruction);
            }
            ArithmeticStatement stm = new ArithmeticStatement(target, operand1, operand2, _ops[instruction.Inst]);
            currentBlock.Statements.Add(stm);
            return stm;
        }
    }
}